跳到主要内容

Effective C++

2. 使用 const, enum, inline 替换 #define

  1. #define 不进入 symbol table,可能导致编译时出错
  2. 类内常量,使用 static const 防止出现多份实体
  3. enum hack:enum { NumTurns = 5 };令 NumTurns 成为 5 的记号名称
  4. 宏可能导致参数被多次核算,使用内联函数替代

3. 尽可能使用 const

  1. const 可以避免很多不应发生的错误
  2. 申明为 mutable 的变量可以被 const 函数更改
  3. 可用 const_cast<>将 const 属性去除
  4. const 函数只可以确保隶属于对象的数据不被更改,但只用指针隶属于对象,则可能造成更改,编程中需注意

4. 确定对象被使用前已被初始化

  1. 使用初始化列表,可以直接调用复制构造函数,避免一次默认构造函数调用
  2. C++ 不保证初始化内置类型,需要显式初始化
  3. non-local static 对象(全局变量等)初始化顺序不确定,需替换成 local static 对象,例如使用函数返回函数内 static 对象的引用(reference-returning)。但在多线程中仍会存在问题,可考虑在单线程启动阶段,手动调用这些函数

5. default 函数

  1. 当类内存在引用、const 成员,编译器拒绝为其生成默认复制赋值函数
  2. 当基类复制赋值函数为 private 时,派生类无法生成默认复制赋值函数

6. 若不使用 default 函数,则应明确拒绝

  1. 可将成员函数声明为 private 并且不予实现,或通过在子类里如此实现,并继承该子类,实现拒绝 default 函数
  2. 通过 delete 拒绝(补充)

7. 为多态基类声明 virtual 析构函数

  1. 通过基类指针删除派生类,若基类析构函数为 non-virtual,则会导致未定义行为,基类部分被删除,而派生类部分则被保留
  2. 声明 virtual 函数时,会使类生成 vtbl(virtual table),其包含 vptr(virtual table pointer)使对象占用空间变大,并且不再与其他语言的相同声明有一样的结构,也就无法将其传递至其他语言所写的函数

8. 别让异常逃离析构函数

  1. 析构函数异常时,会导致程序过早结束,导致其他析构函数无法得到调用

9. 绝不在析构和构造中调用 virtual 函数

  1. 在基类构造函数调用时,派生类还没创建,基类析构函数调用时,派生类已经被销毁。同样,如果基类构造或析构函数中调用的函数存在 virtual 函数,也会导致未定义。
  2. 如有需要,需通过传递参数的方式解决

10. 令 operator=返回一个 reference to *this

11. 在 operator=中处理“自我赋值”

  1. 在赋值时,如果由于别名,指针等问题出现 a=a,可能导致异常,需处理,一个比较好的方法是使用 swap。